:- module(externals, [ignored/1,
		      executable/1,
		      exec_external/1,
		      %add_if_predefined/1,
		      warn/2,
		      getWarning/2,
		      warnings_alert/0,
		      clear_externals/0
		      %add_predefined_type_decl/1
		      ]).

:- use_module(basic_constructs, [directive/1,
				 predefined_type/1
				]).

:- dynamic(ext/1).
:- dynamic(warnings/2).
:- dynamic(predefined_type_decl/1).

clear_externals :-
	retractall(ext(_)),
	retractall(warnings(_,_)),
	retractall(predefined_type_decl(_)).

/*add_predefined_type_decl(T) :-
	assert1(predefined_type_decl(T)).

add_if_predefined(T) :-
        predefined_type(T), !,
	assert1(predefined_type_decl(T))
	;
	true.*/

warn(A,B) :-
	warnings(A,B), ! ; assert(warnings(A,B)).

warnings_alert :-
	warnings(_,_), !,
	writeln('ATTENZIONE, WARNINGS; usa is_warning(Warning,Dettagli).')
	;
	true.

getWarning(A,B) :-
	warnings(A,B).

assert1(E) :-
	E,!;
	assert(E).


%%	recognizing and executing externals

ignored((ignore,_Y)) :- !.
ignored(ignore(_)) :- !.
ignored(X) :-
	directive(X);
	executable(X);
	ext(X).

executable(check(_)).  %% executable externals, i.e. directives
executable(no_check(_)).
executable(ignore(_)).

exec_external(no_check(E)) :- !,
	warn('declared external',E),
        (
	is_list(E) ->
	    forall(member(X,E), assert1(ext(X)))
	    ;
	assert1(ext(E))
	).

exec_external(check(E)) :-
	retractall(ext(E)).

exec_external(ignore(E)) :- !,
	warn('ignored', E).

% 2. predefined term analysis  -------------------------------------

%%	Expr = Op(Args), where Op : Types -> Type
%
/* predefined(Expr,Op,Args,Types,Type) :-
	  predefined_type_decl(Type),
	  predefined_op(Expr,Op,Args,Types,Type).

%%	Context |- T:Type     warning if ambiguous
%	SEE predefined term analysis below
%
predefined_term(T,Type,Context) :-
	once(predefined_t(T,Type,Context)),
       (   copy_term(Context,C1),
	   predefined_t(T,Type1,C1),
	   Type1 \= Type,
	   warn(ambiguous_reconstruction, (Type1,Type)), !
           ;
	   true).

predefined_t(variable(X), Type, Context) :-
	 num_var_assoc(variable(X),Type,Context), !.
predefined_t(Term, Type, Context) :-
	predefined(Term,_Op,Args,Types,Type),
	predefined_ts(Args, Types, Context).

predefined_ts([],[],_).
predefined_ts([T|LT],[Type|LTypes],Context) :-
        predefined_t(T,Type,Context),
	predefined_ts(LT, LTypes,Context).


num_var_assoc(X,Type,L) :- found(X,L,TypeL), !, Type=TypeL.
num_var_assoc(X,Type,L) :- insert(X,Type,L).

found(_X,Z,_) :- var(Z), !, fail.
found(X,[pair(Z,TypeZ)|_],TypeZ) :- X == Z.
found(X,[pair(Z,_)|L],TypeZ) :- X \== Z, found(X,L,TypeZ).

insert(X,Type,Z) :- var(Z), Z = [pair(X,Type)|_].
insert(X,Type,[pair(_,_)|L]) :- insert(X,Type,L).*/






